<template>
  <div style="position: relative" @selectstart.prevent>
    <div v-if="type === '2'" class="verify-img-out" :style="{ height: `${parseInt(setSize.imgHeight) + vSpace}px` }">
      <div class="verify-img-panel" :style="{ width: setSize.imgWidth, height: setSize.imgHeight }">
        <img :src="`data:image/png;base64,${backImgBase}`" alt style="display: block; width: 100%; height: 100%" />
        <div v-show="showRefresh" class="verify-refresh" @click="refresh">
          <i class="iconfont icon-refresh"></i>
        </div>
        <Transition name="tips">
          <span v-if="tipWords" class="verify-tips" :class="passFlag ? 'suc-bg' : 'err-bg'">{{ tipWords }}</span>
        </Transition>
      </div>
    </div>
    <!-- 公共部分 -->
    <div
      class="verify-bar-area"
      :style="{ width: setSize.imgWidth, height: barSize.height, 'line-height': barSize.height }">
      <span class="verify-msg" v-text="text"></span>
      <div
        class="verify-left-bar"
        :style="{
          width: leftBarWidth !== undefined ? leftBarWidth : barSize.height,
          height: barSize.height,
          'border-color': leftBarBorderColor,
          transaction: transitionWidth
        }">
        <span class="verify-msg" v-text="finishText"></span>
        <div
          class="verify-move-block"
          :style="{
            width: barSize.height,
            height: barSize.height,
            'background-color': moveBlockBackgroundColor,
            left: moveBlockLeft,
            transition: transitionLeft
          }"
          @mousedown.prevent="start"
          @touchstart.prevent="start">
          <i :class="['verify-icon iconfont', iconClass]" :style="{ color: iconColor }"></i>
          <div
            v-if="type === '2'"
            class="verify-sub-block"
            :style="{
              width: `${Math.floor((parseInt(setSize.imgWidth) * 47) / 310)}px`,
              height: setSize.imgHeight,
              top: `-${parseInt(setSize.imgHeight) + vSpace}px`,
              'background-size': `${setSize.imgWidth} ${setSize.imgHeight}`
            }">
            <img
              :src="`data:image/png;base64,${blockBackImgBase}`"
              alt
              style="display: block; width: 100%; height: 100%" />
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
  /**
   * VerifySlide
   * @description 滑块
   * */
  import { aesEncrypt } from '../utils/ase'
  import { resetSize } from '../utils/util'
  import { reqGet, reqCheck } from '../api'

  //  "captchaType":"blockPuzzle",
  export default {
    name: 'VerifySlide',
    props: {
      captchaType: {
        type: String
      },
      type: {
        type: String,
        default: '1'
      },
      // 弹出式pop，固定fixed
      mode: {
        type: String,
        default: 'fixed'
      },
      vSpace: {
        type: Number,
        default: 5
      },
      explain: {
        type: String,
        default: '向右滑动完成验证'
      },
      imgSize: {
        type: Object,
        default() {
          return {
            width: '310px',
            height: '155px'
          }
        }
      },
      blockSize: {
        type: Object,
        default() {
          return {
            width: '50px',
            height: '50px'
          }
        }
      },
      barSize: {
        type: Object,
        default() {
          return {
            width: '310px',
            height: '40px'
          }
        }
      }
    },
    data() {
      return {
        secretKey: '', // 后端返回的加密秘钥 字段
        passFlag: '', // 是否通过的标识
        backImgBase: '', // 验证码背景图片
        blockBackImgBase: '', // 验证滑块的背景图片
        backToken: '', // 后端返回的唯一token值
        startMoveTime: '', // 移动开始的时间
        endMovetime: '', // 移动结束的时间
        tipWords: '',
        text: '',
        finishText: '',
        setSize: {
          imgHeight: 0,
          imgWidth: 0,
          barHeight: 0,
          barWidth: 0
        },
        moveBlockLeft: undefined,
        leftBarWidth: undefined,
        // 移动中样式
        moveBlockBackgroundColor: undefined,
        leftBarBorderColor: '#ddd',
        iconColor: undefined,
        iconClass: 'icon-right',
        isStart: false, // 鼠标状态
        showRefresh: true,
        transitionLeft: '',
        transitionWidth: ''
      }
    },
    computed: {
      barArea() {
        return this.$el.querySelector('.verify-bar-area')
      }
    },
    watch: {
      // type变化则全面刷新
      type: {
        immediate: true,
        handler() {
          this.init()
        }
      },
      imgSize: {
        immediate: true,
        handler: 'resetSize'
      },
      barSize: {
        immediate: true,
        handler: 'resetSize'
      }
    },
    created() {
      window.addEventListener('touchmove', this.move)
      window.addEventListener('mousemove', this.move)

      window.addEventListener('touchend', this.end)
      window.addEventListener('mouseup', this.end)
    },
    beforeDestroy() {
      window.removeEventListener('touchmove', this.move)
      window.removeEventListener('mousemove', this.move)

      window.removeEventListener('touchend', this.end)
      window.removeEventListener('mouseup', this.end)
    },
    methods: {
      async init() {
        this.text = this.explain
        await this.getPicture()
        await this.$nextTick()
        this.$parent.$emit('ready', this)
      },
      async resetSize() {
        await this.$nextTick()
        this.setSize = resetSize(this.$el, this.imgSize, this.barSize)
      },
      // 鼠标按下
      start(e) {
        let x
        if (!e.touches) {
          // 兼容PC端
          x = e.clientX
        } else {
          // 兼容移动端
          x = e.touches[0].pageX
        }
        this.startLeft = Math.floor(x - this.barArea.getBoundingClientRect().left)
        this.startMoveTime = +new Date() // 开始滑动的时间
        this.text = ''
        this.moveBlockBackgroundColor = '#337ab7'
        this.leftBarBorderColor = '#337AB7'
        this.iconColor = '#fff'
        this.isStart = true
      },
      // 鼠标移动
      move(e) {
        let x
        if (this.isStart) {
          if (!e.touches) {
            // 兼容PC端
            x = e.clientX
          } else {
            // 兼容移动端
            x = e.touches[0].pageX
          }
          const barAreaLeft = this.barArea.getBoundingClientRect().left
          let moveBlockLeft = x - barAreaLeft // 小方块相对于父元素的left值
          if (moveBlockLeft >= this.barArea.offsetWidth - parseInt(parseInt(this.blockSize.width) / 2) - 2) {
            moveBlockLeft = this.barArea.offsetWidth - parseInt(parseInt(this.blockSize.width) / 2) - 2
          }
          if (moveBlockLeft <= 0) {
            moveBlockLeft = parseInt(parseInt(this.blockSize.width) / 2)
          }
          // 拖动后小方块的left值
          this.moveBlockLeft = `${moveBlockLeft - this.startLeft}px`
          this.leftBarWidth = `${moveBlockLeft - this.startLeft}px`
        }
      },
      // 鼠标松开
      async end() {
        this.endMovetime = +new Date()
        // 判断是否重合
        if (this.isStart) {
          let moveLeftDistance = parseInt((this.moveBlockLeft || '').replace('px', ''))
          moveLeftDistance = (moveLeftDistance * 310) / parseInt(this.setSize.imgWidth)
          const data = {
            captchaType: this.captchaType,
            pointJson: this.secretKey
              ? aesEncrypt(JSON.stringify({ x: moveLeftDistance, y: 5.0 }), this.secretKey)
              : JSON.stringify({ x: moveLeftDistance, y: 5.0 }),
            token: this.backToken
          }
          const response = await reqCheck(data)
          const res = response.data.data
          if (res.repCode === '0000') {
            this.moveBlockBackgroundColor = '#5cb85c'
            this.leftBarBorderColor = '#5cb85c'
            this.iconColor = '#fff'
            this.iconClass = 'icon-check'
            this.showRefresh = false
            if (this.mode === 'pop') {
              setTimeout(() => {
                this.$parent.clickShow = false
                this.refresh()
              }, 1500)
            }
            this.passFlag = true
            this.tipWords = `${((this.endMovetime - this.startMoveTime) / 1000).toFixed(2)}s验证成功`
            const captchaVerification = this.secretKey
              ? aesEncrypt(`${this.backToken}---${JSON.stringify({ x: moveLeftDistance, y: 5.0 })}`, this.secretKey)
              : `${this.backToken}---${JSON.stringify({ x: moveLeftDistance, y: 5.0 })}`
            setTimeout(() => {
              this.tipWords = ''
              this.$parent.closeBox()
              this.$parent.$emit('success', { captchaVerification })
            }, 1000)
          } else {
            this.moveBlockBackgroundColor = '#d9534f'
            this.leftBarBorderColor = '#d9534f'
            this.iconColor = '#fff'
            this.iconClass = 'icon-close'
            this.passFlag = false
            setTimeout(this.refresh, 1000)
            this.$parent.$emit('error', this)
            this.tipWords = '验证失败'
            setTimeout(() => {
              this.tipWords = ''
            }, 1000)
          }

          this.isStart = false
        }
      },
      refresh() {
        this.showRefresh = true
        this.finishText = ''

        this.transitionLeft = 'left .3s'
        this.moveBlockLeft = 0

        this.leftBarWidth = undefined
        this.transitionWidth = 'width .3s'

        this.leftBarBorderColor = '#ddd'
        this.moveBlockBackgroundColor = '#fff'
        this.iconColor = '#000'
        this.iconClass = 'icon-right'

        this.getPicture()
        setTimeout(() => {
          this.transitionWidth = ''
          this.transitionLeft = ''
          this.text = this.explain
        }, 300)
      },
      // 请求背景图片和验证图片
      async getPicture() {
        const data = {
          captchaType: this.captchaType
        }
        const response = await reqGet(data)
        const res = response.data.data
        if (res.repCode === '0000') {
          this.backImgBase = res.repData.originalImageBase64
          this.blockBackImgBase = res.repData.jigsawImageBase64
          this.backToken = res.repData.token
          this.secretKey = res.repData.secretKey
        } else {
          this.tipWords = res.repMsg
        }
      }
    }
  }
</script>
